package it.unipg.bipod.web;

import it.unipg.bipod.applicationLogic.*;
import it.unipg.bipod.dataModel.*;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Vector;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;

/**
 * NuovoBandoBean e' il Bean associato alla pagina di creazione di un nuovo bando.<br>
 * Contiene la sottoclasse pubblica InsegnamentoBean.
 * 
 * @author Lorenzo Porzi
 *
 */
public class NuovoBandoBean extends DefaultBean {
	private SegretarioApplication application;
	
	// Proprietà
	private int annoPubblicazione;
	private int mesePubblicazione;
	private int giornoPubblicazione;
	private int annoScadenza;
	private int meseScadenza;
	private int giornoScadenza;
	
	private String orarioPubblicazione;
	private String orarioScadenza;
	
	private InsegnamentoBean nuovoInsegnamento; // Il nuovo insegnamento in inserimento
	private Vector<InsegnamentoBean> insegnamenti; // Gli insegnamenti inseriti

	/**
	 * Crea un NuovoBandoBean per un nuovo bando.
	 * 
	 * @param application la DocenteApplication associata a questo oggetto.
	 */
	public NuovoBandoBean(SegretarioApplication application) {
		super();
		
		this.application = application;
		
		Calendar now = Calendar.getInstance();
		annoPubblicazione = now.get(Calendar.YEAR);
		mesePubblicazione = now.get(Calendar.MONTH);
		giornoPubblicazione = now.get(Calendar.DAY_OF_MONTH);
		orarioPubblicazione = now.get(Calendar.HOUR_OF_DAY) + ":" + now.get(Calendar.MINUTE);
		
		now.add(Calendar.DATE, 30);
		annoScadenza = now.get(Calendar.YEAR);
		meseScadenza = now.get(Calendar.MONTH);
		giornoScadenza = now.get(Calendar.DAY_OF_MONTH);
		orarioScadenza = now.get(Calendar.HOUR_OF_DAY) + ":" + now.get(Calendar.MINUTE);
		
		nuovoInsegnamento = new InsegnamentoBean();
		insegnamenti = new Vector<InsegnamentoBean>();
	}
	
	/* ----------------------------------
	 * Setters e getters per le proprietà
	 * ---------------------------------- */

	public int getAnnoPubblicazione() {
		return annoPubblicazione;
	}

	public void setAnnoPubblicazione(int annoPubblicazione) {
		this.annoPubblicazione = annoPubblicazione;
	}

	public int getMesePubblicazione() {
		return mesePubblicazione + 1;
	}

	public void setMesePubblicazione(int mesePubblicazione) {
		this.mesePubblicazione = mesePubblicazione - 1;
	}

	public int getGiornoPubblicazione() {
		return giornoPubblicazione;
	}

	public void setGiornoPubblicazione(int giornoPubblicazione) {
		this.giornoPubblicazione = giornoPubblicazione;
	}

	public int getAnnoScadenza() {
		return annoScadenza;
	}

	public void setAnnoScadenza(int annoScadenza) {
		this.annoScadenza = annoScadenza;
	}

	public int getMeseScadenza() {
		return meseScadenza + 1;
	}

	public void setMeseScadenza(int meseScadenza) {
		this.meseScadenza = meseScadenza - 1;
	}

	public int getGiornoScadenza() {
		return giornoScadenza;
	}

	public void setGiornoScadenza(int giornoScadenza) {
		this.giornoScadenza = giornoScadenza;
	}
	
	public String getOrarioPubblicazione() {
		return orarioPubblicazione;
	}
	
	public String getOrarioScadenza() {
		return orarioScadenza;
	}
	
	/**
	 * @return il nuovo insegnamento in corso di inserimento
	 */
	public InsegnamentoBean getNuovoInsegnamento() {
		return nuovoInsegnamento;
	}
	
	/* --------------------------------
	 * Metodi per l'estrazione dei dati
	 * -------------------------------- */
	
	/**
	 * @return un array con i corsi disponibili.
	 */
	public Corso[] getCorsi() {
		try {
			return application.getCorsi();
		} catch (ApplicationException e) {
			Corso[] corsi = {};
			return corsi;
		}
	}
	
	/**
	 * @return un array con gli insegnamenti finora inseriti.
	 */
	public InsegnamentoBean[] getInsegnamenti() {
		return insegnamenti.toArray(new InsegnamentoBean[0]);
	}
	
	/* ---------------------
	 * Metodi di navigazione
	 * --------------------- */
	
	/**
	 * Pubblica il bando incapsulato da questo bean.<br>
	 * Questo metodo utilizza le seguenti proprieta' di presentation.ini:
	 * <ul>
	 *   <li><b>msgErroreNessunInsegnamento</b>: il messaggio visualizzato quando non si sono inseriti insegnamenti.</li>
	 *   <li><b>msgDateErrate</b>: il messaggio visualizzato quando le date inserite non sono valide da un punto di vista temporale.</li>
	 *   <li><b>msgPubblicazioneBandoRiuscita</b>: il messaggio visualizzato quando la pubblicazione riesce.</li>
	 *   <li><b>msgErrorePubblicazioneBando</b>: il messaggio visualizzato quando la pubblicazione non riesce.</li>
	 *   <li><b>msgDateNonValide</b>: il messaggio visualizzato quando le date inserite non sono valide da un punto di vista formale.</li>
	 * </ul>
	 * 
	 * @return la pagina di destinazione: {@code null} in caso di errore, "/pages/segretario-bandi" in caso di successo.
	 */
	public String pubblicaBando() {
		// Controlla che ci siano insegnamenti
		if (insegnamenti.size() == 0) {
			addWarnMessage(getSettings().getProperty("msgErroreNessunInsegnamento"));
			return null;
		}
		
		Timestamp dataPubblicazione = creaData(annoPubblicazione, mesePubblicazione, giornoPubblicazione);
		Timestamp dataScadenza = creaData(annoScadenza, meseScadenza, giornoScadenza);
		
		// Valida le date
		if (dataPubblicazione == null || dataScadenza == null) {
			addWarnMessage(getSettings().getProperty("msgDateNonValide"));
			return null;
		}
		
		try {
			// Pubblica il bando
			Insegnamento[] insegnamentiDaInserire = new Insegnamento[insegnamenti.size()];			
			for (int i = 0; i < insegnamenti.size(); ++i)
				insegnamentiDaInserire[i] = insegnamenti.get(i).getInsegnamento();			
			application.pubblicaBando(insegnamentiDaInserire, dataPubblicazione, dataScadenza);
			
			addInfoMessage(getSettings().getProperty("msgPubblicazioneBandoRiuscita"));
			
			return "/pages/segretario-bandi";
		} catch (ApplicationException e) {
			addWarnMessage(getSettings().getProperty("msgErrorePubblicazioneBando"));
			return null;
		} catch (IllegalArgumentException e) {
			addWarnMessage(getSettings().getProperty("msgDateBandoErrate"));
			return null;
		}
	}
	
	/**
	 * InsegnamentoBean incapsula un insegnamento fornendo alcune funzionalita' aggiuntive.<br>
	 * Permette di aggiungere ed eliminare l'insegnamento da quelli appartenenti al bando
	 * in corso di compilazione.
	 * 
	 * @author Lorenzo Porzi
	 *
	 */
	public class InsegnamentoBean {
		private Insegnamento insegnamento; // L'insegnamento incapsulato
		private Corso corso; // Il corso dell'insegnamento
		
		/**
		 * Crea un nuovo InsegnamentoBean "vuoto".
		 */
		public InsegnamentoBean() {
			corso = new Corso(0, "");
			insegnamento = new Insegnamento();
		}
		
		/* ----------------------------------
		 * Setters e getters per le proprietà
		 * ---------------------------------- */
		
		public void setCorso(Corso corso) {
			this.corso = corso;
			insegnamento.setCorso(corso.getIdCorso());
		}
		
		public void setNome(String nome) {
			insegnamento.setNome(nome);
		}
		
		public void setSsd(String ssd) {
			insegnamento.setSsd(ssd);
		}
		
		public void setCfu(int cfu) {
			insegnamento.setCfu(cfu);
		}
		
		public Insegnamento getInsegnamento() {
			return insegnamento;
		}
		
		public String getNome() {
			return insegnamento.getNome();
		}
		
		public String getSsd() {
			return insegnamento.getSsd();
		}
		
		public int getCfu() {
			return insegnamento.getCfu();
		}
		
		public Corso getCorso() {
			return corso;
		}
		
		public String getNomeCorso() {
			return corso.getNome();
		}
		
		public int getOre() {
			return insegnamento.getOre();
		}
		
		public void setOre(int ore) {
			insegnamento.setOre(ore);
		}
		
		public String getCompenso() {
			return insegnamento.getCompenso();
		}
		
		public void setCompenso(String compenso) {
			insegnamento.setCompenso(compenso);
		}
		
		/* ---------------------
		 * Metodi di navigazione
		 * --------------------- */
		
		/**
		 * Aggiunge l'insegnamento al bando.
		 */
		public void aggiungi() {
			insegnamenti.add(nuovoInsegnamento);
			
			nuovoInsegnamento = new InsegnamentoBean();
		}
		
		/**
		 * Rimuove l'insegnamento dal bando.
		 */
		public void elimina() {
			insegnamenti.remove(this);
		}
	}
	
	/* ------------
	 * Altri metodi
	 * ------------ */
	
	/**
	 * @return l'implementazione di {@link javax.faces.convert.Converter} necessaria per gestire il
	 * menu' di selezione dei corsi.
	 */
	public javax.faces.convert.Converter getCorsoConverter() {
		return new javax.faces.convert.Converter() {		
			@Override
			public Object getAsObject(FacesContext context, UIComponent component,
					String value) {
				Corso corsoTrovato = null;
			
				for (Corso corso : getCorsi())
					if (corso.getNome().equals(value))
						corsoTrovato = corso;
			
				return corsoTrovato;
			}

			@Override
			public String getAsString(FacesContext context, UIComponent component,
					Object value) {
				Corso corso = (Corso)value;
			
				return corso.getNome();
			}		
		};		
	}
	
	/**
	 * Crea un oggetto {@link java.sql.Timestamp} a partire da anno mese e giorno.
	 * 
	 * @param anno
	 * @param mese
	 * @param giorno
	 * @return la data creata oppure {@code null} se i parametri non sono validi.
	 */
	private Timestamp creaData(int anno, int mese, int giorno) {
		Calendar calendar = GregorianCalendar.getInstance();
		
		calendar.set(Calendar.YEAR, anno);	
		
		if (mese > calendar.getActualMaximum(Calendar.MONTH) || mese < calendar.getActualMinimum(Calendar.MONTH))
			return null;		
		calendar.set(Calendar.MONTH, mese);
		
		if (giorno > calendar.getActualMaximum(Calendar.DAY_OF_MONTH) || giorno < calendar.getActualMinimum(Calendar.DAY_OF_MONTH))
			return null;		
		calendar.set(Calendar.DAY_OF_MONTH, giorno);
		
		return new Timestamp(calendar.getTimeInMillis());
	}
}
